﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;

namespace SimpleORM
{
    public abstract class DataSource : IDObject, IDataSource
    {
        #region Properties

        public abstract string ProviderName { get; }
        public abstract string ConnectionString { get; }

        #endregion

        #region Fields

        #region Fields - Static

        private static Hashtable htDataSources;

        #endregion

        #endregion

        #region Ctor

        static DataSource()
        {
            InstallDataSources();
        }

        public DataSource(string cntStringName)
            : this(ConfigurationManager.ConnectionStrings[cntStringName].ProviderName,
                   ConfigurationManager.ConnectionStrings[cntStringName].ConnectionString)
        {
        }

        public DataSource(string providerName, string cntString)
        {
            OnInitialize(providerName, cntString);
        }

        #endregion

        #region Methods

        #region Methods - Public

        public virtual IDataSourceSchema CreateSchema()
        {
            throw new NotImplementedException();
        }

        #endregion

        #region Methods - Override

        protected abstract void OnInitialize(string providerName, string cntString);

        public override string ToString()
        {
            return string.Format("{0}#{1}", ProviderName, ConnectionString);
        }

        public override object Clone()
        {
            return Activator.CreateInstance(this.GetType(), ProviderName, ConnectionString);
        }

        #endregion

        #region Methods - Static

        #region Methods - Static - Public

        public static IDataSource Create(string cntStringName)
        {
            ConnectionStringSettings css = ConfigurationManager.ConnectionStrings[cntStringName];
            IDataSource ds = Create(css.ProviderName, css.ConnectionString);

            return ds;
        }

        public static T Create<T>(string cntStringName) where T : IDataSource
        {
            return (T)Create(cntStringName);
        }

        public static T Create<T>(string providerName, string cntString) where T : IDataSource
        {
            return (T)Create(providerName, cntString);
        }

        public static IDataSource Create(string providerName, string cntString)
        {
            Type type = Get(providerName);
            if (type == null)
                throw new KeyNotFoundException(providerName);

            return Activator.CreateInstance(
                type, new object[] { providerName, cntString }) as IDataSource;
        }

        #endregion

        #region Methods - Static - Private

        private static void InstallDataSources()
        {
            htDataSources = new Hashtable();

            DataSourceSettings cfg = DataSourceSettings.GetContext();
            if (cfg == null)
            {
                //Tracker.WriteLine(new TrackerObject
                //{
                //    EventID = EdProvider.langLoadDataSourceContextFail,
                //    Grade = eMessageGrade.Warn,
                //    Description = new EdProvider().GetName(EdProvider.langLoadDataSourceContextFail),
                //    Source = typeof(Provider).FullName,
                //});

                return;
            }

            foreach (DataSourceElement pe in cfg.Providers)
                Register(pe.Name, Type.GetType(pe.Type, true));
        }

        private static void Register(string name, Type type)
        {
            lock (htDataSources)
                htDataSources[name] = type;
        }

        private static Type Get(string name)
        {
            lock (htDataSources)
                return htDataSources[name] as Type;
        }

        #endregion

        #endregion

        #endregion
    }
}
